#include "CCmd.h"
#include "CCFile.h"

#include <vector>
#include <ostream>
#include <exception>

#include <boost/filesystem.hpp>

CCmd::CCmd(int argc, char* argv[]):
	m_inputFile(0)
{
	m_compilerOpt.add_options()
		("compiler", bpo::value< std::string >(), "Compiler" )
		("include-path,I", bpo::value< std::vector<std::string> >()->composing() ,"Include path")
		("input", bpo::value< std::string >(), "Input file")
		("output,o", bpo::value< std::string >(), "Output obj");
	m_compilerPositionalOpt.add("compiler", 1);
	m_compilerPositionalOpt.add("input", 1);


	parseInput(argc,argv);
}

CCmd::~CCmd(void)
{

}

void CCmd::parseInput( int argc, char* argv[] )
{
	boost::filesystem::path pt = boost::filesystem::current_path();
	std::cout << "path:" << std::string(pt.string()) << std::endl;

	try 
	{		
		bpo::store( bpo::command_line_parser(argc,argv).options(m_compilerOpt).allow_unregistered().positional(m_compilerPositionalOpt).run(), m_varMapOpt );
		bpo::notify( m_varMapOpt );
	}
	catch( std::exception& e)
	{
		std::cout << "Exception:" << e.what() << std::endl;
	}

	try
	{
		bpo::parsed_options  parsedOptions = bpo::command_line_parser(argc,argv).options(m_compilerOpt).positional(m_compilerPositionalOpt).allow_unregistered().run();
		std::vector< std::string > compilerOptions = bpo::collect_unrecognized( parsedOptions.options , bpo::exclude_positional );
		for( size_t i = 0; i< compilerOptions.size(); i++ )
		{
			m_compilerFlags.push_back( compilerOptions.at(i) );
		}
	}
	catch ( std::exception& e)
	{
		std::cout << e.what() << std::endl;	
	}

	if ( m_varMapOpt.count("include-path") )
	{
		try
		{
			std::vector< std::string > includePaths =  m_varMapOpt["include-path"].as< std::vector< std::string >  >();
			for( size_t i = 0; i< includePaths.size(); i++ )
			{
				m_IDirectories.push_back( includePaths.at(i) );
			}
		}
		catch( std::exception& e)
		{
			std::cout << e.what() << std::endl;
			return;
		}
	}

	try
	{
		if ( m_varMapOpt.count("compiler"))
		{
			m_compiler = m_varMapOpt["compiler"].as< std::string >();
		}
		if ( m_varMapOpt.count("input"))
		{
			bfs::path absInputFile = bfs::path(m_varMapOpt["input"].as< std::string >());
			m_inputFile = new CCFile( absInputFile );
		}
		if ( m_varMapOpt.count("output"))
		{
			m_outputFile = m_varMapOpt["output"].as< std::string >();
		}	
	}
	catch ( std::exception& e )
	{
		std::cout << e.what() << std::endl;	
	}
}

std::string CCmd::compiler() const
{
	return m_compiler;
}

CCFile * CCmd::input() const
{
	return m_inputFile;
}

std::string CCmd::output() const
{
	bfs::path outFilePath = bfs::path( bfs::current_path() /= m_outputFile );
	return outFilePath.string();
}

std::vector< std::string > CCmd::compilerFlags() const
{
	return m_compilerFlags;
}

std::vector< std::string > CCmd::includeDirectories() const
{
	return m_IDirectories;
}

std::string CCmd::commandLine() const
{
	std::string cmdLine;

	cmdLine.append( m_compiler );
	cmdLine.append( " " );

	for( size_t i = 0; i< m_compilerFlags.size(); i++ )
	{		
		cmdLine.append( m_compilerFlags.at(i) );
		cmdLine.append( " " );
	}


	for( size_t i = 0; i< m_IDirectories.size(); i++ )
	{
		cmdLine.append("-I");
		cmdLine.append( m_IDirectories.at(i) );
		cmdLine.append( " " );
	}

	cmdLine.append( " -o ");
	cmdLine.append( cacheDir().string() );
	cmdLine.append( nativeSeparator() );
	cmdLine.append( input()->fileOutputPath() );
	cmdLine.append( nativeSeparator() );
	cmdLine.append( "obj.o " );

	cmdLine.append( m_inputFile->filePath() );

	std::cout << "CMD:" <<std::endl;
	std::cout << cmdLine << std::endl;


	return cmdLine;
}
